<?php

/**
 * This file is part of the Pagizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Pagizer Core Team <team@pagizer.org>
 * @package     pagizer
 * @subpackage  website
 */

/**
 * Website page document
 */
class m_website_documents_Page extends m_website_documents_PageBase
{	
	private static $instances;
	
	/**
	 * @return m_website_documents_Page
	 */
	public static function createNew()
	{
		return new self();
	}
	
	/**
	 * @return m_website_documents_Page
	 */
	public static function getInstanceByUniqueId($id, $lang = null)
	{
		if(is_null($lang)) $lang = f_core_Context::getInstance()->getLang();
		
		if(!isset(self::$instances[$lang][$id]))
		{
			$cache = f_core_Cache::getInstance();
			
			$key = $cache->getDocumentCacheKey($id, $lang);
			
			if($cache->hasCache($key))
			{
				return $cache->getCacheContent($key);
			}
					
			self::$instances[$lang][$id] = new self($id, $lang);
			
			$cache->putInCache($key, self::$instances[$lang][$id]);
			
			return self::$instances[$lang][$id];		
		}
		
		return self::$instances[$lang][$id];
	}

    /**
     * Magic method for not declared getter and setter
     *
     * @param string $method
     * @param mixed $args
     * @return m_website_documents_Page
     */
	public function __call($method, $args)
	{
		$prefix = substr($method, 0, 3);
		$suffix = strtolower(substr($method, 3));
		
		if($prefix == "set")
		{
			$this->$suffix = $args[0];
			return $this;
		}
		
		if($prefix == "get")
		{
			if(isset($this->$suffix))
			{
				return $this->$suffix;
			}	
			return null;
		}	
	}

    /**
     * Used before saving page document : clear all cache files
     */
    public function postSave()
    {
         f_template_Template::getInstance()->clear_all_cache();
    }

    /**
     * Used after deleting document : delete temporary page
     */
    public function postDelete()
    {
        m_backoffice_services_TempDocService::getInstance()->deleteTempDocument($this->getUniqueId(), $this->getLang());
    }
	
// **************************************************************** BACKOFFICE METHODS	

    /**
     * Get temporary page modification date
     *
     * @return string
     */
    public function getTempModificationDate()
    {
        $tempService = m_backoffice_services_TempDocService::getInstance();
        if($tempService->hasTemporary($this->getUniqueId(), $this->getLang()))
        {
            return $tempService->getTemporaryDocument($this->getUniqueId(), $this->getLang())->getModificationDate();
        }
        return $this->getModificationDate();
    }

    /**
     * Get publication status, if there is a temporary page return validation
     * @return string
     */
    public function getPublicationStatusWithTemp()
    {
        if(m_backoffice_services_TempDocService::getInstance()->hasTemporary($this->getUniqueId(), $this->getLang()))
        {
            return 'VALIDATION';
        }
        return parent::getPublicationstatus();
    }

    /**
     * For slider menu : document must not slide
     *
     * @return boolean
     */
	public function canSlide()
	{
		return false;
	}
	
	/**
	 * Get document icon
     * 
	 * @return string
	 */
	public function getIcon()
	{		
		return "menu_document.png";
	}

    public function getThemeName()
    {
        $websiteTheme = $this->getWebsite()->getTheme();
        return is_null($websiteTheme) ? FRONT_THEME:$websiteTheme;
    }

    public function getTemplate()
    {
        if($this->hasRecordedLayout())
        {
            $layout = $this->getRecordedLayout();
            if(is_object($layout))
            {
                return $layout->getOriginalLayout();
            }
        }
        return parent::getTemplate();
    }

    public function getParentTemplate()
    {
        return parent::getTemplate();
    }

    public function hasRecordedLayout()
    {
        if(preg_match('/^[0-9]+$/', parent::getTemplate()))
        {
            return true;
        }
        return false;
    }

    private $recordedLayout;

    public function getRecordedLayout()
    {
        if($this->hasRecordedLayout())
        {
            if(is_null($this->recordedLayout))
            {
                $docProvider = f_document_Provider::getInstance();

                if($docProvider->checkDocument(parent::getTemplate(), $this->getLang()))
                {
                    $this->recordedLayout = $docProvider->getByUniqueId(parent::getTemplate(), $this->getLang());
                }
            }

            return $this->recordedLayout;
        }

        return null;
    }

    /**
     * Return formatted page template file path, no check if exists (use getTemplateFilePath())
     *
     * @return string
     */
    public function getTemplateFile()
    {
        return HTTP_DIR.DS.'themes'.DS.$this->getThemeName().DS.'frontend'.DS.'layouts'.DS.$this->getTemplate().'.xml';
    }

    /**
     * Check if page template file exist
     * 
     * @return boolean
     */
    public function hasTemplateFile()
    {
        if($this->hasRecordedLayout())
        {
            return true;
        }
        return is_file($this->getTemplateFile());
    }

    /**
     * Get template file path with check if exists
     * 
     * @return string
     */
    public function getTemplateFilePath()
    {
        if($this->hasTemplateFile())
        {
            return $this->getTemplateFile();
        }
        else
        {
            throw new Exception('Template file '.$this->getTemplateFile().' not found !');
        }
    }

    /**
     * Get template label
     * 
     * @return string
     */
    public function getTemplateLabel()
    {
        $xmlObject = f_xml_Xpath::getInstance($this->getTemplateFilePath());

        return $xmlObject->getAttributeValue('label');
    }
	
	/**
	 * Get the page edition ajax url (for slider menu)
     * 
	 * @return string
	 * @param string $lang[optional]
	 * @param string $tabName[optional]
	 */	
	public function getEditUrl($lang = null, $tabName = null)
	{
		if(!is_string($lang) || is_null($lang))
		{
			$lang = f_core_Request::getInstance()->getParameter("docLang", $this->getLang());
		}
		
		if(!$this->isTranslated())
		{
			return f_core_Routing::getUrl("pageTranslate", array("docId" => $this->getUniqueId(), "docLang" => strtolower($lang)));
		}
		
		if(is_null($tabName))
		{
			$tabName = "tabPageStructure";
		}
		
		return f_core_Routing::getUrl("pageEditTab", array("docId" => $this->getUniqueId(), "docLang" => strtolower($lang), "tabAction" => $tabName));
	}

    /**
     * Get the page delete url (for slider menu)
     * 
     * @param string $lang
     * @return string
     */
	public function getDeleteUrl($lang = null)
	{
		if(is_null($lang))
		{
			$lang = f_core_Request::getInstance()->getParameter("docLang", $this->getLang());
		}

		return f_core_Routing::getUrl("deletePage", array("docId" => $this->getUniqueId(), "docLang" => strtolower($lang)));
	}

    public function getUrl($regexp = false)
    {
        $url = parent::getUrl();
        if($regexp == false)
        {
            $url = preg_replace('/\/<(.*)>/', '', $url);
        }
        return $url;
    }
	
	/**
	 * Return the url without the first /
     * 
	 * @return string
	 */
	public function getFormattedUrl()
	{
		if(substr($this->getUrl(),0,1) == "/")
		{
			return substr($this->getUrl(true),1);
		}
		return $this->getUrl();
	}
	
	/**
	 * Return the website document linked to the page
     * 
	 * @return m_website_documents_Website
	 */
	public function getWebsite()
	{
        return f_document_Provider::getInstance()->getByModelAndUniqueId('website/website', $this->getWebsiteId(), $this->getLang());
	}
	
	/**
	 * Return the website url linked to the page
     * 
	 * @return string
	 */
	public function getWebsiteUrl()
	{
		return $this->getWebsite()->getRealUrl();
	}
	
	/**
	 * Return the page url
     * 
	 * @return string
	 */
	public function getCompleteUrl($withHost = false)
	{
        $url = $this->getUrl() == '/' ? '' : $this->getUrl();
		return $withHost ? "http://".$this->getWebsiteUrl().$url: $url;
	}
	
	/**
	 * Get menu where current page is index
     * 
	 * @return object|null
	 */
	public function getIndexMenu()
	{
		$docProvider = f_document_Provider::getInstance();

		$document = $docProvider->loadDocuments("modules_website/menu")
								->whereIsEqual("menuPageId", $this->getUniqueId())
								->retrieveFirstDocument($this->getLang());

		if($document instanceof f_document_BaseDocument)
		{
			return $document;
		}

		return null;
	}
	
	/**
	 * Get body class to apply on page
     * 
	 * @return string
	 */
	public function getBodyClass()
	{        
        if($this->getUrl() == '/')
        {
             $result = 'id="homepage" ';
        }
        else
        {
            $result = 'id="page'.$this->getUniqueId().'" ';
        }

        $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());
        $pageAttributes = $xml->fromXpath("page")->getAttributes();

        if(isset($pageAttributes['class']) && $pageAttributes['class'] != "")
        {
            $result .= ' class="'.$pageAttributes['class'].'"';
        }


		return $result;
	}

    /**
     * Get css path for current page
     *
     * @return string
     */
    public function getStyleDeclarations()
    {
        $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());

        $declarations = $xml->getElementsFromXpath('style/include');

        $result = '';

        if(is_array($declarations) && count($declarations) > 0)
        {
            foreach($declarations as $declaration)
            {
                /* @var $declaration f_xml_XmlElement */
                $for = $declaration->getAttributeValue('for');
                $media = $declaration->getAttributeValue('media');
                $content = $declaration->getContent();
                $browserInfos = f_core_Request::getInstance()->getBrowserInfos();

                if(is_null($for) || $for == $browserInfos['browser'])
                {
                    $result .= "\t\t".'<link rel="stylesheet" type="text/css" href="'.URL_RELATIVE.'/themes/'.$this->getThemeName().'/frontend/css/'.$declaration->getContent().'"';

                    if(!is_null($media))
                    {
                        $result .= ' media="'.$media.'"';
                    }

                    $result .= ' />'."\n";
                }
            }
        }

        return $result;
    }

    /**
     * Get javascript path for current page
     *
     * @return string
     */
    public function getJavascriptDeclarations()
    {
        $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());

        $libs = $xml->getElementsFromXpath('javascript/include');

        $res = array();

        if(is_array($libs) && count($libs) > 0)
        {
            foreach($libs as $lib)
            {
                if(!is_null($lib->getAttributeValue('lib')))
                {
                    $res[] = 'js/lib/'.$lib;
                }
                else
                {
                    $res[] = 'themes/'.$this->getThemeName().'/frontend/js/'.$lib;
                }
            }
        }

        $result = '';

        if(count($res) > 0)
        {
            $result = "\t\t".'<script src="'.URL_RELATIVE.'/?module=backoffice&amp;action=loadExtraHeader&amp;c=auto&amp;f='.join(',', $res).'"></script>';
        }

        return $result;
    }

    public function getRight()
    {
        $value = "";

        $users = m_rights_services_RightsService::getInstance()->getUserByRightsFromDocument($this, "website", "front", "3");
        if(!empty($users))
        {
            $value = implode(" ",$users);
        }

        return $value;
    }

    public function setRight($users)
    {
        $values = array();
        if(!empty($users))
        {
            $values = explode(" ",$users);
        }

        $rightsService = m_rights_services_RightsService::getInstance();
        $pageRight = $rightsService->getUserByRightsFromDocument($this, "website", "front", "3");

        $values = array_merge(array_diff($pageRight, $values),array_diff($values, $pageRight));

        foreach($values as $value)
        {
            $rightsService->saveRightsForDocument($value, "website", $this, "front");
        }

        return $this;
    }
		
// **************************************************************** BLOCKS METHODS		
	
	/**
	 * Extract all blocks parameters in array from current page content
	 *
	 * @return array
	 */
	public function getAllBlocks()
	{
		return $this->smartyBlocksToArray($this->getContent());
	}
	
	/**
	 * Extract blocks parameters in array from a given text content
	 *
	 * @var string $content
	 * @return array
	 */
	public function smartyBlocksToArray($content)
	{
		preg_match_all('`\{block (.*?)\}`', $content, $rawParams);
		$result = array();
	
		if(count($rawParams) > 0)
		{	
			$tmpResult = array();
			
			foreach($rawParams[1] as $key => $rawBlockParams)
			{
				preg_match_all('`(.*?)="(.*?)"`', $rawBlockParams, $params);
				foreach($params[0] as $k => $blockParam)
				{
                    $paramName = trim($params[1][$k]);
                    $value = trim($params[2][$k]);
					$result[$key][$paramName] = $value;
				}

                if($result[$key]['blockIcon'] == 'block.png')
                {
                    $module = $result[$key]['module'];
                    $xmlFile = f_file_Resolver::getInstance()->getOverload(MODULES_DIR.DS.$module.DS."config".DS."blocks.xml");
                    $xmlBlockParams = f_xml_Xpath::getInstance($xmlFile)->getElementFromXpath("block[@action='".$result[$key]['action']."']");
                    $icon = $xmlBlockParams->getAttributeValue('blockIcon', 'block.png');
                    $result[$key]['blockIcon'] = $icon;
                    $rawBlockParams = str_replace('blockIcon="block.png"', 'blockIcon="'.$icon.'"', $rawBlockParams);
                }
                
				$result[$key]['rawValues'] = $rawBlockParams;
			}
			
			foreach($result as $blocks)
			{
                if(!isset($blocks['blockStatus']) || (isset($blocks['blockStatus']) && $blocks['blockStatus'] != 'DELETED'))
                {
                    $tmpResult[$blocks['blockId']] = $blocks;
                }
			}
			$result = $tmpResult;
		}

		return $result;
	}
	
	/**
	 * Extract parameters in array for a given block id in page
	 *
	 * @param integer $blockId
	 * @return array|null
	 */
	public function getBlockById($blockId)
	{
		$result = array();
		
		preg_match_all('`\{block blockId="'.$blockId.'" (.*?)\}`', $this->getContent(), $rawParams);
		
		if(count($rawParams) > 0)
		{	
			$result[0]["blockId"] = $blockId;
			
			foreach($rawParams[1] as $key => $rawBlockParams)
			{
				preg_match_all('`(.*?)="(.*?)"`', $rawBlockParams, $params);
				foreach($params[0] as $blockParam)
				{
					list($paramName, $value) = explode("=", str_replace('"',"",trim($blockParam)));
					$result[$key][$paramName] = $value;
				}
			}
		}
		if(isset($result[0]))
		{		
			return $result[0];
		}
		return null;
	}	
	
	/**
	 * Define block parameters with an array and his id
	 *
	 * @param integer $blockId
	 * @param array $params
	 * @return m_website_documents_Page
	 */
	public function setBlockParamsById($blockId, $params)
	{	
		if(isset($params["rawValues"]))
		{
			unset($params["rawValues"]);
		}	
	
		$newBlock = $this->arrayToSmartyBlock($params);
		$res = preg_replace('`\{block blockId="'.intval($blockId).'" (.*?)\}`', $newBlock, $this->getContent());
	
		$this->setContent($res);
		
		return $this;
	}

    /**
     * Delete current page block by his id
     *
     * @param integer $blockId
     * @return m_website_documents_Page
     */
	public function deleteBlockById($blockId)
	{
		$res = preg_replace('`\{block blockId="'.$blockId.'" (.*?)\}`', "", $this->getContent());
		
		$this->setContent($res);
		
		return $this;
	}
	
	/**
	 * Convert a parameters array into a bs smarty {block} tag
	 *
	 * @param array $array
	 * @return string
	 */
	public function arrayToSmartyBlock($array)
	{
		$result = "{block ";
		foreach($array as $paramName => $paramValue)
		{
			$result .= $paramName.'="'.$paramValue.'" ';
		}
		$result .= "}";
		return $result;
	}

    public function getBlocksByZoneId($zoneId)
    {
        $blocks = $this->getBlocksByZones();

        $result = array();

        foreach($blocks as $k => $block)
        {
            if(strstr($k, 'freeContent'.$zoneId))
            {
                $result[] = $block;
            }
        }

        return $result;
    }
	
	/**
	 * Return a formatted array of all blocks in current page ordered by freeContent zone id
	 * 
	 * @return array
	 */
	public function getBlocksByZones()
	{
		// Read the template        
        if($this->hasRecordedLayout())
        {
            $xml = $this->getRecordedLayout()->getStructure();
            $zones = $xml->fromXpath("//zone")->getElements();
        }
        else
        {
            $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());
            $zones = $xml->fromXpath("structure//zone")->getElements();
        }

        // Get templates zones

        // Get blocks into free content zones into current document
        $freeBlocks = $this->getFreeContents();

        // Init datas
        $result = array();
        $freeZonesCount = 0;

        // For each template zones in xml
        foreach($zones as $key => $zone)
        {
            // Get declared blocks in xml
            $blocks = $zone->getSubElements("block");

            foreach($blocks as $block)
            {
                $blockAttributes = $block->getAttributes();

                // If block in xml is a freeContent zone
                if(isset($blockAttributes['type']) && $blockAttributes['type'] == "freeContent")
                {
                    $freeZonesCount++;

                    // If content in current page for current xml freeContent zone is not empty
                    if($freeBlocks[$freeZonesCount-1] != null)
                    {
                        // Get current page block content in array
                        $zoneContents = $this->smartyBlocksToArray($freeBlocks[$freeZonesCount-1]);

                        // And put in result
                        if(count($zoneContents) > 0)
                        {
                            $count = 0;
                            foreach($zoneContents as $zoneContent)
                            {
                                $count++;
                                $result["freeContent".$freeZonesCount."_".$count] = $zoneContent;
                            }
                        }
                    }
                }
            }
        }

		return $result;
	}

    /**
     * Render page for FRONT-OFFICE
     *
     * @return string
     */
    public function getFormattedPageContent()
    {
        if($this->hasRecordedLayout())
        {
            $layout = $this->getRecordedLayout();
            if(is_object($layout))
            {
                $xml = $this->getRecordedLayout()->getStructure();
            }
            else
            {
                return '';
            }
        }
        else
        {
            $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath())->fromXpath("structure")->asXml();
        }

        $xmlReader = new XMLReader();
        $xmlReader->XML($xml);

        $freeBlocks = $this->getFreeContents();
        $zoneId = 0;

        $result = '';

        $unauthorized = array('zone', 'structure', 'block');

        while($xmlReader->read())
        {
            if($xmlReader->nodeType == XMLReader::ELEMENT)
            {
                switch ($xmlReader->name)
                {
                    case 'zone':
                        $result .= $this->renderZoneContent($xmlReader->readOuterXml(), $zoneId);
                        $zoneId++;
                    break;

                    case 'structure':
                    case 'block':
                    break;

                    default:
                        $result .= '<'.$xmlReader->name;
                        
                        if ($xmlReader->hasAttributes)
                        {
                            while ($xmlReader->moveToNextAttribute())
                            {
                                $result .=  ' '.$xmlReader->name . "=\"" . $xmlReader->value . "\"";
                            }
                            $xmlReader->moveToElement();
                        }
    
                        $result .= '>';

                        if($xmlReader->isEmptyElement)
                        {
                            $result .= '</'.$xmlReader->name.'>';
                        }

                    break;
                }
            }

            if($xmlReader->nodeType == XMLReader::END_ELEMENT)
            {
                if(!in_array($xmlReader->name, $unauthorized))
                {
                    $result .= '</'.$xmlReader->name.'>';
                }
                if($xmlReader->name == 'zone')
                {
                    $result .= '</div>';
                }
            }

        }

        $xmlReader->close();

        return $result;
    }

    /**
     * Render content by zone in xml layout declaration
     * 
     * @param string $xml
     * @param integer $zoneId
     * @return string
     */
    private function renderZoneContent($xml, $zoneId)
    {
        $zone = f_xml_Xpath::getInstance()->fromString($xml)->getElementFromXpath('/zone');

        $blocks = $zone->getSubElements("block");

        $result = '<div id="'.$zone->getAttributeValue('id', 'zone'.$zoneId).'" class="'.$zone->getAttributeValue('class', 'zone'.$zoneId).'" >'."\r\n";
        $user = f_context_User::getInstance()->getUser();

        foreach($blocks as $block)
        {
            $blockAttributes = $block->getAttributes();

            if(!isset($blockAttributes['type']) || $blockAttributes['type'] != "freeContent")
            {
                $result .= $this->arrayToSmartyBlock($blockAttributes);
            }
            else
            {
                $zoneParams = $this->getZoneContentById($zone->getAttributeValue('id', 'zone'.$zoneId), $zone);

                if(count($zoneParams) > 0)
                {
                    foreach($zoneParams as $zoneParam)
                    {
                        $zoneBlocks = isset($zoneParam['blocks']) ? $zoneParam['blocks'] : array();

                        if(count($zoneBlocks) > 0)
                        {
                            foreach($zoneBlocks as $zoneBlock)
                            {
                                if($this->isAuthorized($user, $zoneBlock['blockId']) && (!isset($zoneBlock["blockStatus"]) || $zoneBlock["blockStatus"] != "DELETED"))
                                {
                                    $result .= '{block '.$zoneBlock['rawValues'].'}';
                                }
                            }
                        }
                    }
                }
            }
        }

        return $result;
    }

// **************************************************************** BACKOFFICE DISPLAY METHODS	
	
	/**
	 * Return content from free contents areas
	 * @return 
	 */
	private function getFreeContents()
	{
		preg_match_all('`<!-- freeContent -->(.*?)<!-- /freeContent -->`', $this->getContent(), $divContent);		
		
		return $divContent[1];
	}
	
	/**
	 * Format template by giving blocks in array
	 *
	 * @param array $content
	 * @return html
	 */
	public function formatTemplate($content)
	{
        if($this->hasRecordedLayout())
        {
            $xml = f_xml_Xpath::getInstance()->fromString($this->getRecordedLayout()->getStructure());
            $zones = $xml->fromXpath("//zone")->getElements();
        }
        else
        {
            $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());
            $zones = $xml->fromXpath("structure//zone")->getElements();
        }

        $result = "";

        foreach($zones as $idZone => $zone)
        {
            $freeBlocks = 1;

            $zoneAttr = $zone->getAttributes();

            if(!isset($zoneAttr['type']) || is_null($zoneAttr['type']))
            {
                if($zoneAttr['status'] == "locked")
                {
                    $result .= '<div id="'.$zoneAttr['id'].'"></div>';
                }
                else
                {
                    $blocks = $this->getPageStructure($zone->getSubElements("block"));

                    $result .= '<div id="'.$zoneAttr['id'].'">';

                    foreach($blocks as $block)
                    {
                        if(isset($block['type']) && $block['type'] == "freeContent")
                        {
                            $freeBlockId = 'freeContent'.$idZone.'_'.$freeBlocks++;

                            $result .= "<!-- freeContent -->";
                            if(isset($content[$freeBlockId]) && count($content[$freeBlockId]) > 0)
                            {
                                foreach($content[$freeBlockId] as $k => $contentBlock)
                                {
                                    if($contentBlock['rawValues'] != "")
                                    {
                                        $result .= '{block '.$contentBlock['rawValues'].'}';
                                    }
                                }
                            }
                            $result .= "<!-- /freeContent -->";
                        }
                    }
                    $result .= "</div>";
                }
            }
        }

        if(isset($content['freeContent99_1']) && count($content['freeContent99_1']) > 0)
        {
            $result .= "<!-- freeContent -->";
            foreach($content['freeContent99_1'] as $k => $contentBlock)
            {
                if($contentBlock['rawValues'] != "")
                {
                    $result .= '{block '.$contentBlock['rawValues'].'}';
                }
            }
            $result .= "<!-- /freeContent -->";

        }

		return $result;
	}

    private $usedBlock = array();
    private $unusedBlocks = array();

    public function getUnusedBlocks()
    {
        if(is_array($this->unusedBlocks) && count($this->unusedBlocks) > 0)
        {
            foreach($this->unusedBlocks as $blockId => $unusedBlock)
            {
                $this->unusedBlocks[$blockId]['buttons'] = m_website_services_PageService::getInstance()->getBlockButtons($unusedBlock, $this, $this->getLang());
            }
            return $this->unusedBlocks;
        }
        return array();
    }

	/**
	 * Get template structure for edition in back-office (main page structure edition)
	 *
	 * @return string
	 */
	public function getTemplateStructure()
	{
        if($this->hasRecordedLayout())
        {
            $layout = $this->getRecordedLayout();
            if(is_object($layout))
            {
                $xml = f_xml_Xpath::getInstance()->fromString($layout->getStructure());
                $zones = $xml->fromXpath("//zone")->getElements();
            }
            else
            {
                return '';
            }
        }
        else
        {
            $xml = f_xml_Xpath::getInstance($this->getTemplateFilePath());
            $zones = $xml->fromXpath("structure//zone")->getElements();
        }

        $blockId = 0;
        $result = '';

        foreach($zones as $idZone => $zone)
        {
            $zoneAttr = $zone->getAttributes();

            if(isset($zoneAttr['status']) && $zoneAttr['status'] == "locked")
            {
                $result .= $this->getLockedZoneContent($zoneAttr, $this->getZoneContentById($zoneAttr['id'], $zone));
            }
            else
            {
                if(isset($zoneAttr['type']))
                {
                    switch ($zoneAttr['type'])
                    {
                        case "clear":
                            $result .= '<div style="clear:both" />';
                        break;

                        case "openDiv":
                            $result .= '<div id="edit_'.$zoneAttr['id'].'">';
                        break;

                        case "closeDiv":
                            $result .= '</div>';
                        break;
                    }
                }
                else
                {
                    $result .= $this->getOpenZoneContent($idZone, $zoneAttr, $this->getZoneContentById($zoneAttr['id'], $zone));
                }
            }
        }

		$this->unusedBlocks = array_diff_key($this->getAllBlocks(), $this->usedBlock);
		return $result;
	}
	
	/**
	 * Get content for opened zone 
	 *
	 * @param integer $idZone
	 * @param array $zoneAttributes
	 * @param array $blocks
	 * @return string
	 */
	private function getOpenZoneContent($idZone, $zoneAttributes, $blocks)
	{
		$docProvider = f_document_Provider::getInstance();

        $width = isset($zoneAttributes['width']) ? 'grid_'.$zoneAttributes['width']:'grid_100';

        $result = '<div class="'.$width.'">';
		$result .= '<div id="edit_'.$zoneAttributes['id'].'" class="pageStructureEditZone"><p>'.$zoneAttributes['label'].'</p>'."\r\n";
		
		if(count($blocks) > 0)
		{	
			$blockString = "";	
			$freeBlocks = 1;

			foreach($blocks as $block)
			{
				if(isset($block['status']) && $block['status'] == "locked")
				{
					$result .= $this->getLockedBlock($block);
				}
				else
				{
					if(isset($block['type']) && $block['type'] == "freeContent")
					{
                        $config = f_loader_Config::getInstance()->getParameters('default');
						$result .= '<div id="freeContent'.$idZone.'_'.$freeBlocks++.'" class="ui-sortable freeContentZone">';
						$blockId = 0;
						if(isset($block['blocks']) && count($block['blocks']) > 0)
						{
							foreach($block['blocks'] as $freeBlock)
							{
								$blockId++;

								if(!isset($freeBlock["blockStatus"]) || $freeBlock["blockStatus"] != "DELETED")
								{			
                                    $pageService = m_website_services_PageService::getInstance();

                                    $xmlBlock = $pageService->getXmlBlockParams($freeBlock);

                                    if(!is_null($xmlBlock))
                                    {
                                        $blockIcon = $xmlBlock->getAttributeValue('blockIcon', 'block.png');
                                        $icon = '<img src="'.URL_RELATIVE.'/themes/'.$config['backTheme'].'/backend/medias/icons/1616/'.$blockIcon.'" class="icon16" alt="" title=""/> ';

                                        $userContext = f_context_User::getInstance();

                                        $this->usedBlock[$freeBlock['blockId']] = $freeBlock;

                                        // Already used in AjaxGetBlockButtons.class.php in backoffice module
                                        $rightLink = $pageService->getBlockButtons($freeBlock, $this, f_core_Context::getInstance()->getDisplayLang());

                                        $helpLabel = f_locale_Manager::getLocale('website.locales.blockLabelEdit');

                                        $result .= '<dl id="block_'.$freeBlock['blockId'].'" class="block"><dt>'.$rightLink.$icon.'<span id="editable_'.$this->getUniqueId()."_".$freeBlock['blockId'].'" class="editable toolTip" title="'.$helpLabel.'">'.$freeBlock['blockLabel'].'</span></dt><dd class="rawValues">'.$freeBlock['rawValues'].'</dd></dl>';
                                    }
								}								
							}
						}
						$result .= "</div>";
					}
				}
			}			
		}
			
		$result .= '</div></div>';

		return $result;
	}
	
	/**
	 * Get content for locked zones from xml file
	 * Only use in back-office for structure edition (TabPageStructureAction)
	 *
	 * @param array $zoneAttributes
	 * @param array $blocks
	 * @return string
	 */
	private function getLockedZoneContent($zoneAttributes, $blocks)
	{
		$result = '<div id="edit_'.$zoneAttributes['id'].'" class="pageStructureEditZone locked"><p>'.$zoneAttributes['label'].'</p>'."\r\n";
		
		if(count($blocks) > 0)
		{
			foreach($blocks as $block)
			{						
				$result .= $this->getLockedBlock($block);
			}
		}
		
		$result .= '</div>';
		
		return $result;
	}
	
	/**
	 * Get locked block string for bo edition
	 * 
	 * @param array $block
	 * @return string
	 */
	private function getLockedBlock($block)
	{
        $config = f_loader_Config::getInstance()->getParameters('default');
        if(!isset($block['blockIcon']) || is_null($block['blockIcon']) || $block['blockIcon'] == '' ) $block['blockIcon'] = 'block_white.png';
        $icon = '<img src="'.URL_RELATIVE.'/themes/'.$config['backTheme'].'/backend/medias/icons/1616/'.$block['blockIcon'].'" class="icon16" alt="" title=""/> ';
        $lockicon = '<img src="'.URL_RELATIVE.'/themes/'.$config['backTheme'].'/backend/medias/icons/1616/lockedblock.png" class="icon16" alt="" title="" style="padding:0"/> ';

        $blockUrl = base64_encode(serialize($block));

        $infosLink = f_core_Routing::getUrl("blockInfos", array("blockId" => $blockUrl, "docId" => $this->getUniqueId(), "docLang" => strtolower($this->getLang())));

        $lockicon .= '<a href="'.URL_RELATIVE.'/bo/#'.$infosLink.'" class="nyroModal"><img src="'.URL_RELATIVE.'/themes/'.$config['backTheme'].'/backend/medias/icons/1616/info.png" class="toolTip icon16" title="'.$block['blockLabel'].' - <table><tr><th>Module</th><td> : '.$block['module'].'</td></tr><tr><th>Action</th><td> : '.$block['action'].'</td></tr></table>" /></a>';
		return '<dl class="blocklocked"><dt><div class="blockEditButtons">'.$lockicon.'</div>'.$icon.$block['blockLabel'].'</dt></dl>'."\r\n";
	}
	
	/**
	 * Get blocks parameters by zone id from content
	 *
	 * @param integer $id
	 * @param f_xml_XmlElement $element
	 * @return array
	 */
	private function getZoneContentById($id, $element = null)
	{
		$result = array();
		
		/* @var $element f_xml_XmlElement */
		if(!is_null($element))
		{
			$result = $this->getPageStructure($element->getSubElements("block"));
		}
		
		preg_match_all('`<div id="'.$id.'">(.*?)</div>`', $this->getContent(), $zoneContent);

		if(isset($zoneContent[1][0]))
		{
			preg_match_all('`<!-- freeContent -->(.*?)<!-- /freeContent -->`', $zoneContent[1][0], $divContent);		
		}
		
		$freeBlocks = 0;
		
		if(is_array($result))
		{
			foreach($result as $key => $block)
			{
				if(isset($block['type']) && $block['type'] == "freeContent")
				{
					if(isset($divContent[1][$freeBlocks]))
					{
						$result[$key]["blocks"] = $this->smartyBlocksToArray($divContent[1][$freeBlocks]);
					}
					$freeBlocks++;
				}
			}			
		}

		return $result;
	}
	
	/**
	 * Get blocks structure from xml file
	 *
	 * @param array|f_xml_XmlElement $blocks
	 * @return array
	 */
	private function getPageStructure($blocks)
	{
		if(is_array($blocks))
		{
			foreach($blocks as $block)
			{
				$attributes = $block->getAttributes();
				if(!isset($attributes['type']))
				{				
					$attributes['status'] = "locked";
				}
				else
				{
					if($attributes['type'] != "freeContent")
					{
						$attributes['status'] = "locked";
					}
				}
				$result[] = $attributes;
			}
		}
		else
		{
			if(!is_null($blocks))
			{
				$attributes = $blocks->getAttributes();
				if(!isset($attributes['type']))
				{				
					$attributes['status'] = "locked";
				}
				else
				{
					if($attributes['type'] != "freeContent")
					{
						$attributes['status'] = "locked";
					}
				}
				$result[] = $attributes;
			}
		}
		
		return $result;
	}
	
	/**
	 * Check if the user can show the page or the block in front
	 * @param $user
	 * @param $blockId
	 * @return bool
	 */
	public function isAuthorized($user, $blockId = null)
	{
		$valid = false;
		
		if($blockId)
		{
			$block = $this->getBlockById($blockId);
			$block["front"] = isset($block["front"]) ? $block["front"] : "";
		}
		
		$rights = isset($block) ? $block["front"] : $this->getRight();
		$tabRights = split(" ", $rights);

		if(empty($rights))
		{
			$valid = true;
		}
		elseif(!isset($user))
		{
			$valid = false;
		}
		else
		{
			$groups = f_relation_Manager::getInstance()->getParentsByDocType($user->getUniqueId(), "modules_users/group");
			$groups[] = $user;
			
			foreach($groups as $group)
			{
				if(in_array($group->getUniqueId(), $tabRights))
				{
					return true;
				}
			}
		}

		return $valid;
	}

    /**
     * Check if the user can have the right or not
     * @param <type> $groupId
     * @param <type> $blockId
     * @param <type> $rule
     * @return <type> bool
     */
    public function hasBlockRights($groupId, $blockId, $rule)
    {
        $rights = $this->getBlockRight($groupId, $blockId);
        
        return (isset($rights[$rule]) && $rights[$rule] > 0);
    }

    /**
     * Return the block rights
     * @param <type> $groupId
     * @param <type> $blockId
     * @return <type> array(5)
     */
    public function getBlockRight($groupId, $blockId)
    {
        $groups = f_relation_Manager::getInstance()->getParentsIdsByDocType($groupId, "modules_users/group");
        $groups[]['parent_id'] = $groupId;

        $keys = array('front', 'read', 'edit', 'add', 'delete');
        $tabRights = array();
        
        $block = $this->getBlockById($blockId);

        $nbGroup = count($groups);
        foreach($groups as $group)
        {
            foreach($keys as $key)
            {
                $value = '1';

                if(isset($block[$key]))
                {
                    if(isset($tabRights[$key]) && ($tabRights[$key] == "2" ||$tabRights[$key] == "4"))
                    {
                        continue;
                    }

                    if($key == 'front')
                    {
                        $groupsBlock = explode(" ", $block[$key]);
                        $success = in_array($group['parent_id'],$groupsBlock);

                        if(!$success)
                        {
                            $value = '0';
                        }
                        else
                        {
                            $value = $group['parent_id'] == $groupId ? '3' : '4';
                        }
                    }
                    else
                    {
                        $groupsBlock = explode("|", $block[$key]);
                        $authorizedGroups = explode(" ", $groupsBlock[0]);
                        $bannedGroups = explode(" ", $groupsBlock[1]);

                        $authorizedGroupsSuccess = in_array($group['parent_id'],$authorizedGroups);
                        $bannedGroupsSuccess = in_array($group['parent_id'],$bannedGroups);

                        if($bannedGroupsSuccess)
                        {
                            $value = '0';
                        }
                        else
                        {
                            if(isset($tabRights[$key]) && $tabRights[$key] == '0')
                            {
                                $value = $authorizedGroupsSuccess ? '1' : '0';
                            }
                            else
                            {
                                $value = $nbGroup == 1 ? '1' : '2';
                            }
                        }
                    }
                }
                else
                {
                    if(isset($tabRights[$key]))
                    {
                        if($tabRights[$key] > 0)
                        {
                            $value = $key == 'front' ? '1' : '2';
                            if($tabRights["front"] == '3')
                            {
                                $value = '4';
                            }
                        }
                    }
                }

                $tabRights[$key] = $value;
            }
        }

        return $tabRights;
    }

    public function setBlockRight($groupId, $blockId, $rule, $rights = null)
    {
        $blockRights = $this->getBlockRight($groupId, $blockId);
        $block = $this->getBlockById($blockId);

        $rights = m_rights_services_RightsService::getInstance()->changeRights($blockRights, $rule, $rights);

        foreach($rights as $key => $right)
        {
            if(isset($block[$key]))
            {
                if($key == "front")
                {
                    $blockRight = explode(" ", $block[$key]);
                    $blockRightKey = array_search($groupId, $blockRight);
                    
                    if($right == "3" && $blockRightKey === false)
                    {
                        $blockRight[] = $groupId;
                    }

                    if($right == "0" && $blockRightKey !== false)
                    {
                        unset($blockRight[$blockRightKey]);
                    }

                    if(empty($blockRight))
                    {
                        unset($block[$key]);
                    }
                    else
                    {
                        $block[$key] = trim(implode(" ", $blockRight));
                    }
                }
                else
                {
                    $groupsBlock = explode("|", $block[$key]);
                    $authorizedGroups = explode(" ", $groupsBlock[0]);
                    $bannedGroups = explode(" ", $groupsBlock[1]);
                    
                    $authorizedGroupsKey = array_search($groupId, $authorizedGroups);
                    $bannedGroupsKey = array_search($groupId, $bannedGroups);

                    if($right == "0")
                    {
                        if($bannedGroupsKey === false)
                        {
                            $bannedGroups[] = $groupId;
                        }

                        if($authorizedGroupsKey !== false)
                        {
                            unset($authorizedGroups[$authorizedGroupsKey]);
                        }
                    }

                    if($right == "1")
                    {
                        if($authorizedGroupsKey === false)
                        {
                            $authorizedGroups[] = $groupId;
                        }

                        if($bannedGroupsKey !== false)
                        {
                            unset($bannedGroups[$bannedGroupsKey]);
                        }
                    }


                    $groupsBlock[0] = trim(implode(" ", $authorizedGroups));
                    $groupsBlock[1] = trim(implode(" ", $bannedGroups));
                    $block[$key] = implode("|",$groupsBlock);
                }
            }
            else
            {
                if($key == "front")
                {
                    if($right == "3")
                    {
                        $block[$key] = $groupId;
                    }
                }
                else
                {
                    $block[$key] = $right == "0" ? '|'.$groupId : '|';
                }
            }
        }

        $this->setBlockParamsById($blockId, $block)->save(false);
        return $this->getBlockRight($groupId, $blockId);
    }

    /**
     * Return document icon for back office search
     * @return string
     */
    public function getBoSearchIcon()
    {
        return m_medias_services_MediaService::getInstance()->getIconPath($this->getIcon());
    }    
}